/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.espier.t9keyboard;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.AsyncQueryHandler;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabaseCorruptException;
import android.database.sqlite.SQLiteDiskIOException;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteFullException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Vibrator;
import android.provider.Contacts.People;
import android.provider.Contacts.Phones;
import android.provider.Contacts.PhonesColumns;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.Settings;
import android.telephony.PhoneNumberFormattingTextWatcher;
import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.Editable;
import android.text.Html;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnCreateContextMenuListener;
import android.view.View.OnFocusChangeListener;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.TranslateAnimation;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.ResourceCursorAdapter;
import android.widget.SlidingDrawer;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;

/**
 * Dialer activity that displays the typical twelve key interface.
 */
public class SearchKeyBoard extends Activity implements View.OnClickListener,
        View.OnLongClickListener, View.OnKeyListener,
        TextWatcher {

    private static final String TAG = "TwelveKeyDialer";

    private static final int STOP_TONE = 1;

    /** The length of DTMF tones in milliseconds */
    private static final int TONE_LENGTH_MS = 150;

    /** The DTMF tone volume relative to other sounds in the stream */
    private static final int TONE_RELATIVE_VOLUME = 80;

    /**
     * Stream type used to play the DTMF tones off call, and mapped to the
     * volume control keys
     */
    private static final int DIAL_TONE_STREAM_TYPE = AudioManager.STREAM_MUSIC;

    /** Play the vibrate pattern only once. */
    private static final int VIBRATE_NO_REPEAT = -1;

    public static final int REQUEST_SEND_CALL = 100;

    private EditText mDigits;
    private EditText mDigitsShow;
    private EditText mSearchEditText;
    private View mDelete;
    // private MenuItem mAddToContactMenuItem;
    private ToneGenerator mToneGenerator;
    private Object mToneGeneratorLock = new Object();
    private View mDialpad;
    // private ListView mDialpadChooser;
    private DialpadChooserAdapter mDialpadChooserAdapter;

    private long mStarKeyPressedTime = 0;

    // determines if we want to playback local DTMF tones.
    private boolean mDTMFToneEnabled;

    // Vibration (haptic feedback) for dialer key presses.
    private Vibrator mVibrator;
    private boolean mVibrateOn;
    private long[] mVibratePattern;

    /**
     * Identifier for intent extra for sending an empty Flash message for CDMA
     * networks. This message is used by the network to simulate a press/depress
     * of the "hookswitch" of a landline phone. Aka "empty flash". TODO: Using
     * an intent extra to tell the phone to send this flash is a temporary
     * measure. To be replaced with an ITelephony call in the future. TODO: Keep
     * in sync with the string defined in OutgoingCallBroadcaster.java in Phone
     * app until this is replaced with the ITelephony API.
     */
    static final String EXTRA_SEND_EMPTY_FLASH = "com.android.phone.extra.SEND_EMPTY_FLASH";

    /**
     * Indicates if we are opening this dialer to add a call from the
     * InCallScreen.
     */
    private boolean mIsAddCallMode;

    private SlidingDrawer mDialerDrawer;
    private ImageButton mShowHideKeypad;
    private ImageView mSearchClear;

    private ListView mContactsListView;
    private ContactsAdapter mAdapter;
    private QueryHandler mQueryHandler;
    private MyContactAdapter mContactAdapter;
    private List<ContactPerson> mContactList;
    private List<MyCallLog> mCallLogList;

    private int mAsyncTaskNumber;
    private boolean notShowOrHideDigitsView;

    private String mSelectedNumber;
    private boolean isDelNumber = false;

    private static final int QUERY_TOKEN = 53;
    public static final Uri PHONES_AND_CALLLOG_CONTENT_URI =
            Uri.parse("content://com.android.contacts/phones_and_calllog");

    public static final Uri CONTACTS_CONTENT_URI = Uri
            .parse("content://com.android.contacts/contacts");

    /** The projection to use when querying the call log table */
    static final String[] PHONES_AND_CALLLOG_PROJECTION = new String[] {
            "_id",
            "number",
            Contacts.DISPLAY_NAME,
            "type",
            "label",
            "dialpad_number_short",
            "dialpad_number_full",
            "dialpad_index_short",
            "dialpad_index_full",
            Contacts.PHOTO_ID,
            "people_id",
            "data_id"
    };

    static final int ID_COLUMN_INDEX = 0;
    static final int NUMBER_COLUMN_INDEX = 1;
    static final int CALLER_NAME_COLUMN_INDEX = 2;
    static final int CALLER_NUMBERTYPE_COLUMN_INDEX = 3;
    static final int CALLER_NUMBERLABEL_COLUMN_INDEX = 4;
    static final int CALLER_NUMBER_SHORT_INDEX = 5;
    static final int CALLER_NUMBER_FULL_INDEX = 6;
    static final int CALLER_NUMBER_INDEX_SHORT_INDEX = 7;
    static final int CALLER_NUMBER_INDEX_FULL_INDEX = 8;
    static final int CALLER_PHOTO_INDEX = 9;
    static final int CALLER_PEOPLE_ID = 10;
    static final int CALLER_DATA_ID = 11;

    static final int DOUBLE_CLICK_TAP = 1000;

    static final String EXTRA_PHONE_ID = "phoneid";
    boolean mIsDsds = false;

    private LinearLayout mLlShowDailpad;
    private ImageButton mIbtnShowdailpad;

    private LinearLayout mContactsListViewLl;
    private LinearLayout mShowDigitsLl;

    private LinearLayout mCreateContactsLl;
    private ImageView mNoDataIv;
    private RelativeLayout mCreateContactsItemRl;
    private RelativeLayout mAddToExistingContactItemRl;

    // jiao add
    private RelativeLayout mSearchLayout;
    private TableRow tableRow;
    private ImageButton mCall;
    private ImageButton mSms;
    private ImageButton mZero;
    private ImageButton mDone;

    private SearchControl control;

    // private MenuWindow mCreateContactMenuWindow;

    private final int NO_CALLLOG_AND_CONTACTS = 100;
    private final int HAVE_CALLLOG_AND_CONTACTS = 101;
    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case NO_CALLLOG_AND_CONTACTS:
                mContactsListView.setVisibility(View.GONE);
                mCreateContactsLl.setVisibility(View.VISIBLE);
                if (mDigits.getText().toString().length() > 3) {
                    mCreateContactsItemRl.setVisibility(View.VISIBLE);
                    mAddToExistingContactItemRl.setVisibility(View.VISIBLE);
                    mNoDataIv.setVisibility(View.GONE);
                } else {
                    mCreateContactsItemRl.setVisibility(View.GONE);
                    mAddToExistingContactItemRl.setVisibility(View.GONE);
                    mNoDataIv.setVisibility(View.VISIBLE);
                }
                break;
            case HAVE_CALLLOG_AND_CONTACTS:
                mContactsListView.setVisibility(View.VISIBLE);
                mCreateContactsLl.setVisibility(View.GONE);
                break;
            default:
                break;
        }
    };
    };

    public static final class ContactsListItemViews {
        TextView line1View;
        TextView labelView;
        TextView numberView;
        ImageView operateButton;
        ImageView photoView;
    }

    public static final class ContactsListViewItemViews {
        ImageView photoView;
        TextView nameView;
        TextView numberView;
        TextView addressView;
    }

    OnScrollListener listViewOnScrollListener = new OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {

            // mDialerDrawer.close();
            // mLlShowDailpad.setVisibility(View.VISIBLE);
            // view.clearFocus();
        }

    };

    OnItemClickListener mContactsListClickListener = new OnItemClickListener() {

        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

            if (!(view.getTag() instanceof ContactsListViewItemViews)) {
                return;
            }
            ContactsListViewItemViews views = (ContactsListViewItemViews) view.getTag();
            TextView tvName = views.nameView;
            TextView tvNumber = views.numberView;
            TextView tvAddress = views.addressView;
            ImageView ivPhotoView = views.photoView;

            String tel = tvNumber.getText().toString();
            boolean isContact = false;
            if (tvAddress.getTag() != null) {
                isContact = ((Boolean) tvAddress.getTag()).booleanValue();
            }

            Log.v(TAG, " isContact is >>>" + isContact);
            if (!isContact) {
                tel = tvAddress.getText().toString();
            }

            notShowOrHideDigitsView = true;
            mDigits.getText().clear();
            analogKeyPressed(tel);
            mLlShowDailpad.setVisibility(View.GONE);
            mDialerDrawer.open();
            // mDialerDrawer.animateToggle();
        }

    };

    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        // Do nothing
    }

    public void onTextChanged(CharSequence input, int start, int before, int changeCount) {
        // Do nothing
    }

    public void afterTextChanged(Editable input) {
        String text = mDigits.getText().toString();
        Log.e(TAG, "++++++++++++++++++++++++++======mDigits text:" + text);
        String textToShow = "";
        text = text.replace(',', 'p');
        text = text.replace(';', 'w');
        textToShow = text;
        mDigitsShow.getText().clear();
        mSearchEditText.getText().clear();
        textToShow = text;
        mDigitsShow.getText().append(textToShow);
        mSearchEditText.getText().append(textToShow);

        setDigitsShowOrHideWithAnima();
        startQuery();
    }

    @Override
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        control = SearchControl.getInstance(this);
        Log.w(TAG, "onCreate :mIsDsds= " + mIsDsds + ",layout id=" + getContentViewResource());
        // Set the content view
        setContentView(getContentViewResource());

        // Load up the resources for the text field and delete button
        Resources r = getResources();

        mShowDigitsLl = (LinearLayout) findViewById(R.id.showDigitsLl);
        mDigits = (EditText) findViewById(R.id.digits);
        mDigitsShow = (EditText) findViewById(R.id.digitsShow);
        Log.w(TAG, "onCreate :mDigits= " + mDigits + ",mDigitsShow=" + mDigitsShow);

        // Check for the presence of the keypad
        View view = findViewById(R.id.one);
        if (view != null) {
            setupKeypad();
        }

        view = findViewById(R.id.backspace);
        view.setOnClickListener(this);
        view.setOnLongClickListener(this);
        mDelete = view;

        mLlShowDailpad = (LinearLayout) findViewById(R.id.showDialPadll);
        mIbtnShowdailpad = (ImageButton) findViewById(R.id.showDialPadBtn);
        mIbtnShowdailpad.setOnClickListener(this);

        // jiao dialpad initView
        mDialerDrawer = (SlidingDrawer) findViewById(R.id.dialer_container);
        mDialpad = (View) findViewById(R.id.dialpad); // This is null in
                                                      // landscape mode
        mSearchEditText = (EditText) findViewById(R.id.dialpad_search);
        mSearchClear = (ImageView) findViewById(R.id.search_img_clear);
        mSearchClear.setOnClickListener(this);

        // jiao keyborad view inint
        mSearchLayout = (RelativeLayout) findViewById(R.id.search_layout);
        tableRow = (TableRow) findViewById(R.id.row_bottom_layout);
        mZero = (ImageButton) findViewById(R.id.zero);
        mDone = (ImageButton) findViewById(R.id.done);
        mCall = (ImageButton) findViewById(R.id.call);
        mSms = (ImageButton) findViewById(R.id.sms);

        // set keyBoard style
        setKeyBoardStyle(0);

        mCreateContactsLl = (LinearLayout) findViewById(R.id.createContactsLl);
        mNoDataIv = (ImageView) findViewById(R.id.noDataIv);
        mCreateContactsItemRl = (RelativeLayout) findViewById(R.id.createContactsItemRl);
        mCreateContactsItemRl.setOnClickListener(this);
        mAddToExistingContactItemRl = (RelativeLayout) findViewById(R.id.addToExistingContactItemRl);
        mAddToExistingContactItemRl.setOnClickListener(this);

        mAdapter = new ContactsAdapter();
        mContactAdapter = new MyContactAdapter();

        mContactsListViewLl = (LinearLayout) findViewById(R.id.contactsListLl);
        mContactsListView = (ListView) findViewById(R.id.contactsListView);
        mContactsListView.setOnItemClickListener(mContactsListClickListener);
        // mContactsListView.setOnCreateContextMenuListener(mContactsListContextMenuListener);
        mContactsListView.setOnScrollListener(listViewOnScrollListener);
        mContactsListView.setOnFocusChangeListener(new OnFocusChangeListener() {

            @Override
            public void onFocusChange(View v, boolean hasFocus) {

            }
        });
        mContactsListView.setAdapter(mContactAdapter);
        // mContactsListView.setOnItemSelectedListener(mContactsSelectedListener);
        mQueryHandler = new QueryHandler(this);

        if (!resolveIntent() && icicle != null) {
            super.onRestoreInstanceState(icicle);
        }

        // If the mToneGenerator creation fails, just continue without it. It is
        // a local audio signal, and is not as important as the dtmf tone
        // itself.
        synchronized (mToneGeneratorLock) {
            if (mToneGenerator == null) {
                try {
                    mToneGenerator = new ToneGenerator(AudioManager.STREAM_NOTIFICATION,
                            TONE_RELATIVE_VOLUME);
                } catch (RuntimeException e) {
                    Log.w(TAG, "Exception caught while creating local tone generator: " + e);
                    mToneGenerator = null;
                }
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        synchronized (mToneGeneratorLock) {
            if (mToneGenerator != null) {
                mToneStopper.removeMessages(STOP_TONE);
                mToneGenerator.release();
                mToneGenerator = null;
            }
        }
    }

    @Override
    protected void onRestoreInstanceState(Bundle icicle) {
        // Do nothing, state is restored in onCreate() if needed
    }

    protected void maybeAddNumberFormatting() {
        mDigits.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
    }

    /**
     * Overridden by subclasses to control the resource used by the content
     * view.
     */
    protected int getContentViewResource() {
        return R.layout.twelve_key_dialer_dsds;
    }

    private boolean resolveIntent() {
        boolean ignoreState = false;
        return ignoreState;
    }

    // protected void setFormattedDigits(String data) {
    // // strip the non-dialable numbers out of the data string.
    // String dialString = PhoneNumberUtils.extractNetworkPortion(data);
    // dialString = PhoneNumberUtils.formatNumber(dialString);
    // dialString = PhoneNumberUtils.stripSeparators(dialString);
    // if (!TextUtils.isEmpty(dialString)) {
    // Editable digits = mDigits.getText();
    // digits.replace(0, digits.length(), dialString);
    // // for some reason this isn't getting called in the digits.replace call
    // above..
    // // but in any case, this will make sure the background drawable looks
    // right
    // afterTextChanged(digits);
    // }
    // }

    @Override
    protected void onNewIntent(Intent newIntent) {
        setIntent(newIntent);
        resolveIntent();
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // This can't be done in onCreate(), since the auto-restoring of the
        // digits
        // will play DTMF tones for all the old digits if it is when
        // onRestoreSavedInstanceState()
        // is called. This method will be called every time the activity is
        // created, and
        // will always happen after onRestoreSavedInstanceState().
        mDigits.addTextChangedListener(this);
    }

    private void setupKeypad() {
        // Setup the listeners for the buttons
        View view = findViewById(R.id.one);
        view.setOnClickListener(this);
        // view.setOnLongClickListener(this);

        view = findViewById(R.id.two);
        view.setOnClickListener(this);
        view.setOnLongClickListener(this);

        view = findViewById(R.id.three);
        view.setOnClickListener(this);
        // view.setOnLongClickListener(this);

        view = findViewById(R.id.four);
        view.setOnClickListener(this);
        // view.setOnLongClickListener(this);

        view = findViewById(R.id.five);
        view.setOnClickListener(this);
        // view.setOnLongClickListener(this);

        view = findViewById(R.id.six);
        view.setOnClickListener(this);
        // view.setOnLongClickListener(this);

        view = findViewById(R.id.seven);
        view.setOnClickListener(this);
        // view.setOnLongClickListener(this);

        view = findViewById(R.id.eight);
        view.setOnClickListener(this);
        // view.setOnLongClickListener(this);

        view = findViewById(R.id.nine);
        view.setOnClickListener(this);
        // view.setOnLongClickListener(this);

        view = findViewById(R.id.star);
        // view.setOnClickListener(this);

        view = findViewById(R.id.zero);
        view.setOnClickListener(this);
        // view.setOnLongClickListener(this);

        // jiao add
        view = findViewById(R.id.zero_v4);
        view.setOnClickListener(this);

        view = findViewById(R.id.call);
        view.setOnClickListener(this);

        view = findViewById(R.id.sms);
        view.setOnClickListener(this);

        findViewById(R.id.pound).setOnClickListener(this);
    }

    @Override
    protected void onResume() {
        super.onResume();

        // retrieve the DTMF tone play back setting.
        mDTMFToneEnabled = Settings.System.getInt(getContentResolver(),
                Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;

        // if the mToneGenerator creation fails, just continue without it. It is
        // a local audio signal, and is not as important as the dtmf tone
        // itself.
        synchronized (mToneGeneratorLock) {
            if (mToneGenerator == null) {
                try {
                    mToneGenerator = new ToneGenerator(AudioManager.STREAM_NOTIFICATION,
                            TONE_RELATIVE_VOLUME);
                } catch (RuntimeException e) {
                    Log.w(TAG, "Exception caught while creating local tone generator: " + e);
                    mToneGenerator = null;
                }
            }
        }

        // Potentially show hint text in the mDigits field when the user
        // hasn't typed any digits yet. (If there's already an active call,
        // this hint text will remind the user that he's about to add a new
        // call.)
        //
        // TODO: consider adding better UI for the case where *both* lines
        // are currently in use. (Right now we let the user try to add
        // another call, but that call is guaranteed to fail. Perhaps the
        // entire dialer UI should be disabled instead.)
        if (phoneIsInUse()) {
            mDigitsShow.setHint(R.string.dialerDialpadHintText);
        } else {
            // Common case; no hint necessary.
            mDigitsShow.setHint(null);

            // Also, a sanity-check: the "dialpad chooser" UI should NEVER
            // be visible if the phone is idle!
            // showDialpadChooser(false);
        }

        if (!mDialerDrawer.isOpened()) {
            // mDialerDrawer.animateToggle();
            mDialerDrawer.open();
        }
        setDigitsShowOrHideWithAnima();
        startQuery();
        mContactList = ContactsCalllogDBUtils.getContactList(getApplicationContext(), null);
        mCallLogList = ContactsCalllogDBUtils.getCallLogs(getApplicationContext(), null);
        afterQuery();

    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        if (hasFocus) {
            // Hide soft keyboard, if visible (it's fugly over button dialer).
            // The only known case where this will be true is when launching the
            // dialer with
            // ACTION_DIAL via a soft keyboard. we dismiss it here because we
            // don't
            // have a window token yet in onCreate / onNewIntent
            InputMethodManager inputMethodManager = (InputMethodManager)
                    getSystemService(Context.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(mDigitsShow.getWindowToken(), 0);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        synchronized (mToneGeneratorLock) {
            if (mToneGenerator != null) {
                mToneStopper.removeMessages(STOP_TONE);
                mToneGenerator.release();
                mToneGenerator = null;
            }
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // We never show a menu if the "choose dialpad" UI is up.
        return true;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        Log.e(TAG, "keyCode  " + keyCode);
        switch (keyCode) {
            // case KeyEvent.KEYCODE_BACK:
            // //System.out.println(TAG + "onKeyDown keyCode is KEYCODE_BACK");
            // //System.out.println(TAG +
            // "isActivityRequestSendCall:"+isActivityRequestSendCall);
            // if(isActivityRequestSendCall){
            // setResult(Activity.RESULT_OK,mRequestIntent);
            // finish();
            // }
            // break;
            case KeyEvent.KEYCODE_CALL: {
                long callPressDiff = SystemClock.uptimeMillis() - event.getDownTime();
                if (callPressDiff >= ViewConfiguration.getLongPressTimeout()) {
                    // Launch voice dialer
                    Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    try {
                        startActivity(intent);
                    } catch (ActivityNotFoundException e) {
                    }
                }
                return true;
            }
            case KeyEvent.KEYCODE_1: {
                long timeDiff = SystemClock.uptimeMillis() - event.getDownTime();
                if (timeDiff >= ViewConfiguration.getLongPressTimeout()) {
                    // Long press detected, call voice mail
                    callVoicemail();
                    return true;
                }
            }
        }
        if (mDialerDrawer.isOpened()) {
            switch (keyCode) {
                case KeyEvent.KEYCODE_STAR:
                    String numberNow = mDigits.getText().toString();
                    long currentTime = SystemClock.elapsedRealtime();
                    if (numberNow.endsWith("*")
                            && currentTime - mStarKeyPressedTime < DOUBLE_CLICK_TAP) {
                        mDigits.getText().delete(mDigits.length() - 1, mDigits.length());
                        mDigits.append(",");
                    } else if (numberNow.endsWith(",")
                            && currentTime - mStarKeyPressedTime < DOUBLE_CLICK_TAP) {
                        mDigits.getText().delete(mDigits.length() - 1, mDigits.length());
                        mDigits.append(";");
                    } else if (numberNow.endsWith(";")
                            && currentTime - mStarKeyPressedTime < DOUBLE_CLICK_TAP) {
                        mDigits.getText().delete(mDigits.length() - 1, mDigits.length());
                        mDigits.append("*");
                    } else {
                        mDigits.onKeyDown(keyCode, event);
                    }
                    mStarKeyPressedTime = currentTime;
                    return true;
                case KeyEvent.KEYCODE_0:
                case KeyEvent.KEYCODE_1:
                case KeyEvent.KEYCODE_2:
                case KeyEvent.KEYCODE_3:
                case KeyEvent.KEYCODE_4:
                case KeyEvent.KEYCODE_5:
                case KeyEvent.KEYCODE_6:
                case KeyEvent.KEYCODE_7:
                case KeyEvent.KEYCODE_8:
                case KeyEvent.KEYCODE_9:
                case KeyEvent.KEYCODE_POUND:
                    mDigits.onKeyDown(keyCode, event);
                    return true;
            }
        }
        return super.onKeyDown(keyCode, event);
    }

    private void analogKeyPressed(String number) {
        Log.e(TAG, "analogKeyPressed  number " + number);
        char key;
        for (int i = 0; i < number.length(); i++) {
            // key=Integer.parseInt(number.substring(i,i+1));
            key = number.charAt(i);
            switch (key) {
                case '0':
                    keyPressed(KeyEvent.KEYCODE_0);
                    break;
                case '1':
                    keyPressed(KeyEvent.KEYCODE_1);
                    break;
                case '2':
                    keyPressed(KeyEvent.KEYCODE_2);
                    break;
                case '3':
                    keyPressed(KeyEvent.KEYCODE_3);
                    break;
                case '4':
                    keyPressed(KeyEvent.KEYCODE_4);
                    break;
                case '5':
                    keyPressed(KeyEvent.KEYCODE_5);
                    break;
                case '6':
                    keyPressed(KeyEvent.KEYCODE_6);
                    break;
                case '7':
                    keyPressed(KeyEvent.KEYCODE_7);
                    break;
                case '8':
                    keyPressed(KeyEvent.KEYCODE_8);
                    break;
                case '9':
                    keyPressed(KeyEvent.KEYCODE_9);
                    break;
                case '#':
                    keyPressed(KeyEvent.KEYCODE_POUND);
                    break;
                case '*':
                    keyPressed(KeyEvent.KEYCODE_STAR);
                    break;

                default:
                    break;
            }
        }
    }

    private void keyPressed(int keyCode) {
        Log.e(TAG, "keyPressed  " + keyCode);
        // vibrate();
        KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
        control.setKeyCode(keyCode);
        mDigits.onKeyDown(keyCode, event);
    }

    public boolean onKey(View view, int keyCode, KeyEvent event) {
        switch (view.getId()) {
            case R.id.digitsShow:
                if (keyCode == KeyEvent.KEYCODE_ENTER) {
                    placeCall();
                    return true;
                }
                break;
        }
        return false;
    }

    public void onClick(View view) {
        Log.e(TAG, "id " + view.getId());
        switch (view.getId()) {
            case R.id.one: {
                playTone(ToneGenerator.TONE_DTMF_1);
                keyPressed(KeyEvent.KEYCODE_1);
                return;
            }
            case R.id.two: {
                playTone(ToneGenerator.TONE_DTMF_2);
                keyPressed(KeyEvent.KEYCODE_2);
                return;
            }
            case R.id.three: {
                playTone(ToneGenerator.TONE_DTMF_3);
                keyPressed(KeyEvent.KEYCODE_3);
                return;
            }
            case R.id.four: {
                playTone(ToneGenerator.TONE_DTMF_4);
                keyPressed(KeyEvent.KEYCODE_4);
                return;
            }
            case R.id.five: {
                playTone(ToneGenerator.TONE_DTMF_5);
                keyPressed(KeyEvent.KEYCODE_5);
                return;
            }
            case R.id.six: {
                playTone(ToneGenerator.TONE_DTMF_6);
                keyPressed(KeyEvent.KEYCODE_6);
                return;
            }
            case R.id.seven: {
                playTone(ToneGenerator.TONE_DTMF_7);
                keyPressed(KeyEvent.KEYCODE_7);
                return;
            }
            case R.id.eight: {
                playTone(ToneGenerator.TONE_DTMF_8);
                keyPressed(KeyEvent.KEYCODE_8);
                return;
            }
            case R.id.nine: {
                playTone(ToneGenerator.TONE_DTMF_9);
                keyPressed(KeyEvent.KEYCODE_9);
                return;
            }
            case R.id.zero_v4:
            case R.id.zero: {
                playTone(ToneGenerator.TONE_DTMF_0);
                keyPressed(KeyEvent.KEYCODE_0);
                return;
            }
            case R.id.pound: {
                playTone(ToneGenerator.TONE_DTMF_P);
                keyPressed(KeyEvent.KEYCODE_POUND);
                return;
            }
            case R.id.star: {
                Toast.makeText(this, "star  ", Toast.LENGTH_SHORT).show();
                playTone(ToneGenerator.TONE_DTMF_S);
                String numberNow = mDigits.getText().toString();
                long currentTime = SystemClock.elapsedRealtime();
                if (numberNow.endsWith("*")
                        && currentTime - mStarKeyPressedTime < DOUBLE_CLICK_TAP) {
                    mDigits.getText().delete(mDigits.length() - 1, mDigits.length());
                    mDigits.append(",");
                } else if (numberNow.endsWith(",")
                        && currentTime - mStarKeyPressedTime < DOUBLE_CLICK_TAP) {
                    mDigits.getText().delete(mDigits.length() - 1, mDigits.length());
                    mDigits.append(";");
                } else if (numberNow.endsWith(";")
                        && currentTime - mStarKeyPressedTime < DOUBLE_CLICK_TAP) {
                    mDigits.getText().delete(mDigits.length() - 1, mDigits.length());
                    mDigits.append("*");
                } else {
                    keyPressed(KeyEvent.KEYCODE_STAR);
                }
                mStarKeyPressedTime = currentTime;
                return;
            }
            case R.id.backspace: {
                isDelNumber = true;
                playTone(ToneGenerator.TONE_DTMF_B);
                keyPressed(KeyEvent.KEYCODE_DEL);
                return;
            }
            case R.id.digitsShow:
                break;
            case R.id.done_v4:
            case R.id.done: // done set diapad visiable
                playTone(ToneGenerator.TONE_DTMF_D);
                break;
            case R.id.call: // call
                playTone(ToneGenerator.TONE_DTMF_C);
                break;
            case R.id.sms: // sms
                playTone(ToneGenerator.TONE_DTMF_S);
                break;
            // case R.id.callmark1: {
            // placeCall(1);
            // return;
            // }
            case R.id.showDialPadBtn:
                mDialerDrawer.open();
                System.out.println("show DialPadBtn ");
                mLlShowDailpad.setVisibility(View.GONE);

                // mDialerDrawer.animateToggle();
                return;

            case R.id.createContactsItemRl: {
                // playTone(ToneGenerator.TONE_DTMF_A);
                if (mDigits.getText() != null && mDigits.getText().length() != 0
                        && mDialerDrawer.isOpened()) {
                    // Intent intent = new
                    // Intent("com.android.contacts.action.SHOW_OR_CREATE_CONTACT");
                    // intent.setData(Uri.fromParts("tel",
                    // mDigits.getText().toString(), null));
                    // intent.putExtra(Insert.PHONE, mDigits.getText());
                    // intent.setType(People.CONTENT_ITEM_TYPE);
                    // startActivity(intent);

                    // if(mCreateContactMenuWindow==null){
                    // initCreateContactMenuWindow();
                    // }
                    // mCreateContactMenuWindow.show();
                }
                return;
            }
            case R.id.addToExistingContactItemRl: {
                if (mDigits.getText() != null && mDigits.getText().length() != 0
                        && mDialerDrawer.isOpened()) {
                    Toast.makeText(this, "go to add to existing contact", 0).show();
                }
            }
                return;
        }
    }

    public boolean onLongClick(View view) {
        final Editable digits = mDigits.getText();
        int id = view.getId();
        switch (id) {
            case R.id.backspace: {
                digits.clear();
                mDigitsShow.setTextSize(25);
                return true;
            }
            case R.id.one: {
                if (digits.length() == 0) {
                    callVoicemail();
                    return true;
                }
                return false;
            }
            case R.id.two:
                return rapidCall(2);
            case R.id.three:
                return rapidCall(3);
            case R.id.four:
                return rapidCall(4);
            case R.id.five:
                return rapidCall(5);
            case R.id.six:
                return rapidCall(6);
            case R.id.seven:
                return rapidCall(7);
            case R.id.eight:
                return rapidCall(8);
            case R.id.nine:
                return rapidCall(9);
            case R.id.zero: {
                keyPressed(KeyEvent.KEYCODE_PLUS);
                return true;
            }
            case R.id.digitsShow:
                return true;
        }
        return false;
    }

    private boolean rapidCall(int key) {
        Uri rapidUri = ContentUris.withAppendedId(
                Uri.parse("content://com.android.contacts/speed_dial"), key);
        Cursor c = getContentResolver().query(rapidUri,
                new String[] {
                    Data.DATA1
                }, null, null, null);
        if (c != null) {
            if (c.moveToFirst()) {
                Intent intent = new Intent(Intent.ACTION_DIAL,
                        Uri.fromParts("tel", c.getString(0), null));
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);
                mDigits.getText().clear();
                finish();
                c.close();
                return true;
            } else {
                c.close();
                Log.d(TAG, "in rapid dial cursor.moveToFirst is null!");
                return false;
            }
        } else {
            Log.d(TAG, "rapid dial cursor is null!");
            return false;
        }
    }

    void callVoicemail() {
        Intent intent = new Intent(Intent.ACTION_DIAL,
                Uri.fromParts("voicemail", "", null));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
        mDigits.getText().clear();
        finish();
    }

    void placeCall(int phoneid) {
        String number = null;
        if (mDialerDrawer.isOpened()) {
            number = mDigits.getText().toString();
        } else {
            if (mSelectedNumber != null) {
                number = mSelectedNumber;
            }
        }
        if (number == null || !TextUtils.isGraphic(number)) {
            // There is no number entered.
            playTone(ToneGenerator.TONE_PROP_NACK);
            return;
        }
        Intent testintent = new Intent(Intent.ACTION_CALL,
                Uri.fromParts("tel", number, null));
        startActivity(testintent);
        mDigits.getText().clear();
    }

    void placeCall() {
        String number = null;
        if (mDialerDrawer.isOpened()) {
            number = mDigits.getText().toString();
        } else {
            if (mSelectedNumber != null) {
                number = mSelectedNumber;
            }
        }
        if (number == null || !TextUtils.isGraphic(number)) {
            // There is no number entered.
            playTone(ToneGenerator.TONE_PROP_NACK);
            return;
        }
        Intent intent = new Intent(Intent.ACTION_DIAL,
                Uri.fromParts("tel", number, null));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
        mDigits.getText().clear();
        // finish();
    }

    Handler mToneStopper = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case STOP_TONE:
                    synchronized (mToneGeneratorLock) {
                        if (mToneGenerator == null) {
                            Log.w(TAG, "mToneStopper: mToneGenerator == null");
                        } else {
                            mToneGenerator.stopTone();
                        }
                    }
                    break;
            }
        }
    };

    /**
     * Plays the specified tone for TONE_LENGTH_MS milliseconds. The tone is
     * played locally, using the audio stream for phone calls. Tones are played
     * only if the "Audible touch tones" user preference is checked, and are NOT
     * played if the device is in silent mode.
     * 
     * @param tone a tone code from {@link ToneGenerator}
     */
    void playTone(int tone) {
        // if local tone playback is disabled, just return.
        if (!mDTMFToneEnabled) {
            return;
        }

        // Also do nothing if the phone is in silent mode.
        // We need to re-check the ringer mode for *every* playTone()
        // call, rather than keeping a local flag that's updated in
        // onResume(), since it's possible to toggle silent mode without
        // leaving the current activity (via the ENDCALL-longpress menu.)
        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        int ringerMode = audioManager.getRingerMode();
        if ((ringerMode == AudioManager.RINGER_MODE_SILENT)
                || (ringerMode == AudioManager.RINGER_MODE_VIBRATE)) {
            return;
        }

        synchronized (mToneGeneratorLock) {
            if (mToneGenerator == null) {
                Log.w(TAG, "playTone: mToneGenerator == null, tone: " + tone);
                return;
            }

            // Remove pending STOP_TONE messages
            mToneStopper.removeMessages(STOP_TONE);

            // Start the new tone (will stop any playing tone)
            mToneGenerator.startTone(tone);
            mToneStopper.sendEmptyMessageDelayed(STOP_TONE, TONE_LENGTH_MS);
        }
    }

    /**
     * Brings up the "dialpad chooser" UI in place of the usual Dialer elements
     * (the textfield/button and the dialpad underneath). We show this UI if the
     * user brings up the Dialer while a call is already in progress, since
     * there's a good chance we got here accidentally (and the user really
     * wanted the in-call dialpad instead). So in this situation we display an
     * intermediate UI that lets the user explicitly choose between the in-call
     * dialpad ("Use touch tone keypad") and the regular Dialer ("Add
     * call").  (Or, the option "Return to call in progress" just goes back to
     * the in-call UI with no dialpad at all.)
     * 
     * @param enabled If true, show the "dialpad chooser" instead of the regular
     *            Dialer UI
     */
    // private void showDialpadChooser(boolean enabled) {
    // if (enabled) {
    // // Log.i(TAG, "Showing dialpad chooser!");
    // mContactsList.setVisibility(View.GONE);
    // if (mDialerDrawer != null) mDialerDrawer.setVisibility(View.GONE);
    // mDialpadChooser.setVisibility(View.VISIBLE);
    //
    // // Instantiate the DialpadChooserAdapter and hook it up to the
    // // ListView. We do this only once.
    // if (mDialpadChooserAdapter == null) {
    // mDialpadChooserAdapter = new DialpadChooserAdapter(this);
    // mDialpadChooser.setAdapter(mDialpadChooserAdapter);
    // }
    // } else {
    // // Log.i(TAG, "Displaying normal Dialer UI.");
    // mContactsList.setVisibility(View.VISIBLE);
    // if (mDialerDrawer != null) mDialerDrawer.setVisibility(View.VISIBLE);
    // mDialpadChooser.setVisibility(View.GONE);
    // }
    // }

    /**
     * @return true if we're currently showing the "dialpad chooser" UI.
     */
    // private boolean dialpadChooserVisible() {
    // return mDialpadChooser.getVisibility() == View.VISIBLE;
    // }

    /**
     * Simple list adapter, binding to an icon + text label for each item in the
     * "dialpad chooser" list.
     */
    private static class DialpadChooserAdapter extends BaseAdapter {
        private LayoutInflater mInflater;

        // Simple struct for a single "choice" item.
        static class ChoiceItem {
            String text;
            Bitmap icon;
            int id;

            public ChoiceItem(String s, Bitmap b, int i) {
                text = s;
                icon = b;
                id = i;
            }
        }

        // IDs for the possible "choices":
        static final int DIALPAD_CHOICE_USE_DTMF_DIALPAD = 101;
        static final int DIALPAD_CHOICE_RETURN_TO_CALL = 102;
        static final int DIALPAD_CHOICE_ADD_NEW_CALL = 103;

        private static final int NUM_ITEMS = 3;
        private ChoiceItem mChoiceItems[] = new ChoiceItem[NUM_ITEMS];

        public DialpadChooserAdapter(Context context) {
            // Cache the LayoutInflate to avoid asking for a new one each time.
            mInflater = LayoutInflater.from(context);

            // Initialize the possible choices.
            // TODO: could this be specified entirely in XML?

            // - "Use touch tone keypad"
            mChoiceItems[0] = new ChoiceItem(
                    context.getString(R.string.dialer_useDtmfDialpad),
                    BitmapFactory.decodeResource(context.getResources(),
                                                 R.drawable.ic_dialer_fork_tt_keypad),
                    DIALPAD_CHOICE_USE_DTMF_DIALPAD);

            // - "Return to call in progress"
            mChoiceItems[1] = new ChoiceItem(
                    context.getString(R.string.dialer_returnToInCallScreen),
                    BitmapFactory.decodeResource(context.getResources(),
                                                 R.drawable.ic_dialer_fork_current_call),
                    DIALPAD_CHOICE_RETURN_TO_CALL);

            // - "Add call"
            mChoiceItems[2] = new ChoiceItem(
                    context.getString(R.string.dialer_addAnotherCall),
                    BitmapFactory.decodeResource(context.getResources(),
                                                 R.drawable.ic_dialer_fork_add_call),
                    DIALPAD_CHOICE_ADD_NEW_CALL);
        }

        public int getCount() {
            return NUM_ITEMS;
        }

        /**
         * Return the ChoiceItem for a given position.
         */
        public Object getItem(int position) {
            return mChoiceItems[position];
        }

        /**
         * Return a unique ID for each possible choice.
         */
        public long getItemId(int position) {
            return position;
        }

        /**
         * Make a view for each row.
         */
        public View getView(int position, View convertView, ViewGroup parent) {
            // When convertView is non-null, we can reuse it (there's no need
            // to reinflate it.)
            // if (convertView == null) {
            // convertView =
            // mInflater.inflate(R.layout.dialpad_chooser_list_item, null);
            // }
            //
            // TextView text = (TextView) convertView.findViewById(R.id.text);
            // text.setText(mChoiceItems[position].text);
            //
            // ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
            // icon.setImageBitmap(mChoiceItems[position].icon);

            return convertView;
        }
    }

    /**
     * Handle clicks from the dialpad chooser.
     */
    // public void onItemClick(AdapterView parent, View v, int position, long
    // id) {
    // DialpadChooserAdapter.ChoiceItem item =
    // (DialpadChooserAdapter.ChoiceItem) parent.getItemAtPosition(position);
    // int itemId = item.id;
    // switch (itemId) {
    // case DialpadChooserAdapter.DIALPAD_CHOICE_USE_DTMF_DIALPAD:
    // // Log.i(TAG, "DIALPAD_CHOICE_USE_DTMF_DIALPAD");
    // // Fire off an intent to go back to the in-call UI
    // // with the dialpad visible.
    // returnToInCallScreen(true);
    // break;
    //
    // case DialpadChooserAdapter.DIALPAD_CHOICE_RETURN_TO_CALL:
    // // Log.i(TAG, "DIALPAD_CHOICE_RETURN_TO_CALL");
    // // Fire off an intent to go back to the in-call UI
    // // (with the dialpad hidden).
    // returnToInCallScreen(false);
    // break;
    //
    // case DialpadChooserAdapter.DIALPAD_CHOICE_ADD_NEW_CALL:
    // // Log.i(TAG, "DIALPAD_CHOICE_ADD_NEW_CALL");
    // // Ok, guess the user really did want to be here (in the
    // // regular Dialer) after all. Bring back the normal Dialer UI.
    // showDialpadChooser(false);
    // break;
    //
    // default:
    // Log.w(TAG, "onItemClick: unexpected itemId: " + itemId);
    // break;
    // }
    // }

    /**
     * Returns to the in-call UI (where there's presumably a call in progress)
     * in response to the user selecting "use touch tone keypad" or
     * "return to call" from the dialpad chooser.
     */
    private void returnToInCallScreen(boolean showDialpad) {
        // try {
        // ITelephony phone =
        // ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
        // if (phone != null) phone.showCallScreenWithDialpad(showDialpad);
        // } catch (RemoteException e) {
        // Log.w(TAG, "phone.showCallScreenWithDialpad() failed", e);
        // }

        // Finally, finish() ourselves so that we don't stay on the
        // activity stack.
        // Note that we do this whether or not the showCallScreenWithDialpad()
        // call above had any effect or not! (That call is a no-op if the
        // phone is idle, which can happen if the current call ends while
        // the dialpad chooser is up. In this case we can't show the
        // InCallScreen, and there's no point staying here in the Dialer,
        // so we just take the user back where he came from...)
        finish();
    }

    /**
     * @return true if the phone is "in use", meaning that at least one line is
     *         active (ie. off hook or ringing or dialing).
     */
    private boolean phoneIsInUse() {
        boolean phoneInUse = false;
        // try {
        // ITelephony phone =
        // ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
        // if (phone != null) phoneInUse = !phone.isIdle();
        // } catch (RemoteException e) {
        // Log.w(TAG, "phone.isIdle() failed", e);
        // }
        return phoneInUse;
    }

    private void measureView(View view) {
        int w = View.MeasureSpec.makeMeasureSpec(0,
                View.MeasureSpec.UNSPECIFIED);
        int h = View.MeasureSpec.makeMeasureSpec(0,
                View.MeasureSpec.UNSPECIFIED);
        view.measure(w, h);
    }

    private void setDigitsShowOrHideWithAnima() {
        if (notShowOrHideDigitsView) {
            notShowOrHideDigitsView = false;
            return;
        }
        if (mDigits.getText().toString().length() > 0) {
            if (mShowDigitsLl.getVisibility() == View.GONE) {
                mShowDigitsLl.setVisibility(View.VISIBLE);
                measureView(mShowDigitsLl);
                TranslateAnimation rAnimation = new TranslateAnimation(0, 0,
                        -mShowDigitsLl.getMeasuredHeight(), 0);
                rAnimation.setDuration(300);
                mContactsListViewLl.startAnimation(rAnimation);
            }
            mShowDigitsLl.setVisibility(View.VISIBLE);
        } else {
            if (mShowDigitsLl.getVisibility() == View.VISIBLE) {
                // measureView(mShowDigitsLl);
                TranslateAnimation rAnimation = new TranslateAnimation(0, 0,
                        mShowDigitsLl.getMeasuredHeight(), 0);
                // Log.d(TAG,
                // "mShowDigitsLl.getMeasuredHeight():"+mShowDigitsLl.getMeasuredHeight());
                rAnimation.setDuration(300);
                mContactsListViewLl.startAnimation(rAnimation);

                TranslateAnimation rAnimation2 = new TranslateAnimation(0, 0,
                                0, -mShowDigitsLl.getMeasuredHeight());
                rAnimation2.setDuration(300);
                mShowDigitsLl.startAnimation(rAnimation2);
            }
            mShowDigitsLl.setVisibility(View.GONE);
        }
    }

    private void startQuery() {

        final String cond = mDigits.getText().toString();

        mAsyncTaskNumber++;
        new AsyncTask<SearchKeyBoard, Void, SearchKeyBoard>() {

            @Override
            protected SearchKeyBoard doInBackground(SearchKeyBoard... params) {
                if (mAsyncTaskNumber == 1) {
                    // mContactList=ContactsCalllogDBUtils.getContacts(getApplicationContext(),cond);

                    mContactList = control.getContanctsList();
                    if (mContactList == null)
                        mContactList = ContactsCalllogDBUtils.getContactList(
                                getApplicationContext(), cond);
                }
                mAsyncTaskNumber--;
                return params[0];
            }

            @Override
            protected void onPostExecute(SearchKeyBoard activity) {
                if (mAsyncTaskNumber > 1) {
                    return;
                }
                afterQuery();
            };

        }.execute(this);

    }

    private void afterQuery() {
        if (mCallLogList != null && mContactList != null && mCallLogList.size() > 0
                && mContactList.size() > 0) {
            ArrayList<String> nameList = new ArrayList<String>();
            for (int i = 0; i < mCallLogList.size(); i++) {
                nameList.add(mCallLogList.get(i).getName());
            }
            int size = mContactList.size();
            for (int i = size - 1; i >= 0; i--) {
                if (nameList.contains(mContactList.get(i).getName())) {
                    mContactList.remove(i);
                }
            }
        }
        mContactAdapter.notifyDataSetChanged();
        if (mCallLogList == null && mContactList == null) {
            Message message = this.mHandler.obtainMessage(this.NO_CALLLOG_AND_CONTACTS);
            message.sendToTarget();
        } else if (mCallLogList.size() + mContactList.size() < 1) {
            Message message = this.mHandler.obtainMessage(this.NO_CALLLOG_AND_CONTACTS);
            message.sendToTarget();
        } else {
            Message message = this.mHandler.obtainMessage(this.HAVE_CALLLOG_AND_CONTACTS);
            message.sendToTarget();
        }
    }

    /**
     * Shared builder used by {@link #formatPhoneNumber(String)} to minimize
     * allocations when formatting phone numbers.
     */
    private static final SpannableStringBuilder sEditable = new SpannableStringBuilder();

    /**
     * Invalid formatting type constant for {@link #sFormattingType}.
     */
    private static final int FORMATTING_TYPE_INVALID = -1;

    /**
     * Cached formatting type for current {@link Locale}, as provided by
     * {@link PhoneNumberUtils#getFormatTypeForLocale(Locale)}.
     */
    private static int sFormattingType = FORMATTING_TYPE_INVALID;

    /**
     * Format the given phone number using
     * {@link PhoneNumberUtils#formatNumber(android.text.Editable, int)}. This
     * helper method uses {@link #sEditable} and {@link #sFormattingType} to
     * prevent allocations between multiple calls.
     * <p>
     * Because of the shared {@link #sEditable} builder, <b>this method is not
     * thread safe</b>, and should only be called from the GUI thread.
     */
    private String formatPhoneNumber(String number) {
        // Cache formatting type if not already present
        if (sFormattingType == FORMATTING_TYPE_INVALID) {
            sFormattingType = PhoneNumberUtils.getFormatTypeForLocale(Locale.getDefault());
        }

        sEditable.clear();
        sEditable.append(number);

        PhoneNumberUtils.formatNumber(sEditable, sFormattingType);
        return PhoneNumberUtils.stripSeparators(sEditable.toString());
    }

    final class MyContactAdapter extends BaseAdapter {
        LayoutInflater mLayoutInflater = LayoutInflater.from(getApplicationContext());

        @Override
        public int getCount() {
            if ((mContactList == null && mCallLogList == null)
                    || mCallLogList.size() + mContactList.size() == 0) {
                return 0;
            }
            if (mCallLogList == null || mCallLogList.size() == 0) {
                return mContactList.size() + 1;
            }
            if (mContactList == null || mContactList.size() == 0) {
                return mCallLogList.size() + 1;
            }
            return mCallLogList.size() + mContactList.size() + 2; // mContactList.size()
        }

        @Override
        public Object getItem(int position) {
            if (mCallLogList == null || mCallLogList.size() == 0) {
                if (position == 0) {
                    return null;
                } else {
                    return mContactList.get(position - 1);
                }
            }
            if (mContactList == null || mContactList.size() == 0) {
                if (position == 0) {
                    return null;
                } else {
                    return mCallLogList.get(position - 1);
                }
            }
            if (position == 0 || position == mCallLogList.size() + 1) {
                return null;
            } else if (position < mCallLogList.size() + 1) {
                return mCallLogList.get(position - 1);
            } else {
                return mContactList.get(position - mCallLogList.size() - 2);
            }
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view = null;

            if (mCallLogList == null || mCallLogList.size() == 0) {
                if (position == 0) {
                    return getDivideView(R.string.calllog_contacts);
                } else {
                    view = getContactsItemContentView(mContactList.get(position - 1), convertView);
                }
            } else if (mContactList == null || mContactList.size() == 0) {
                if (position == 0) {
                    return getDivideView(R.string.calllog_recents);
                } else {
                    view = getCallLogItemContentView(mCallLogList.get(position - 1), convertView);
                }
            } else {
                if (position == 0 || position == mCallLogList.size() + 1) {
                    if (position == 0) {
                        return getDivideView(R.string.calllog_recents);
                    } else {
                        return getDivideView(R.string.calllog_contacts);
                    }
                } else if (position < mCallLogList.size() + 1) {
                    view = getCallLogItemContentView(mCallLogList.get(position - 1), convertView);
                } else {
                    view = getContactsItemContentView(
                            mContactList.get(position - mCallLogList.size() - 2), convertView);
                }
            }
            return view;
        }

        private View getCallLogItemContentView(MyCallLog callLog, View convertView) {
            View view;
            ContactsListViewItemViews tempView;
            if (convertView == null || !(convertView.getTag() instanceof ContactsListViewItemViews)) {
                view = getContentView();
            } else {
                view = convertView;
            }
            tempView = (ContactsListViewItemViews) view.getTag();

            tempView.nameView.setText(callLog.getName());
            String logMsg = CallLogDateUtils.getDateString(getApplicationContext(),
                    callLog.getCallDate())
                    + "  "
                    + getResources().getString(callLog.getCallTypeResId())
                    + "   "
                    + CallLogDateUtils.getDurationTimeString(getApplicationContext(),
                            callLog.getDuration());
            tempView.numberView.setText(logMsg);
            tempView.addressView.setText(callLog.getNumber());
            return view;
        }

        private View getContactsItemContentView(ContactPerson contact, View convertView) {
            View view;
            ContactsListViewItemViews tempView;
            if (convertView == null || !(convertView.getTag() instanceof ContactsListViewItemViews)) {
                view = getContentView();
            } else {
                view = convertView;
            }
            tempView = (ContactsListViewItemViews) view.getTag();

            if (contact.getSimType() == 1) {
                tempView.photoView.setBackgroundResource(R.drawable.sim1);
            } else if (contact.getSimType() == 2) {
                tempView.photoView.setBackgroundResource(R.drawable.sim2);
            } else {
                tempView.photoView.setBackgroundResource(R.drawable.ic_contact_list_picture);
            }

            // tempView.photoView.setImageBitmap(contact.getPhoto());
            tempView.nameView.setText(contact.getName());
            tempView.numberView.setText(ContactsDBUtils.getPhoneText(contact.getPhone()));
            tempView.addressView.setText(contact.getName());
            tempView.addressView.setTag(new Boolean(true)); // if it is the
                                                            // ContactItem or
                                                            // CallLogItem
            return view;
        }

        private View getContentView() {
            View view = mLayoutInflater.inflate(R.layout.twelve_key_dialer_listitem, null);
            ContactsListViewItemViews tempView = new ContactsListViewItemViews();
            tempView.photoView = (ImageView) view.findViewById(R.id.photoIv);
            tempView.nameView = (TextView) view.findViewById(R.id.nameTv);
            tempView.numberView = (TextView) view.findViewById(R.id.numberTv);
            tempView.addressView = (TextView) view.findViewById(R.id.addressTv);
            view.setTag(tempView);
            return view;
        }

        private View getDivideView(int strResId) {
            View view = mLayoutInflater.inflate(R.layout.twelve_key_dialer_divideitem, null);
            TextView divideTitleTv = (TextView) view.findViewById(R.id.divideTitleTv);
            divideTitleTv.setText(strResId);
            return view;
        }

    }

    final class ContactsAdapter extends ResourceCursorAdapter {

        private CharSequence[] mLabelArray;

        private OnClickListener mAddListener = new OnClickListener() {
            public void onClick(View v) {
                String number = (String) v.getTag();
                Intent intent = new Intent("com.android.contacts.action.SHOW_OR_CREATE_CONTACT");
                intent.setData(Uri.fromParts("tel", number, null));
                startActivity(intent);
            }
        };

        private OnClickListener mAddListenerPeople = new OnClickListener() {
            public void onClick(View v) {
                String peopleId = (String) v.getTag();
                Log.v(TAG, "people id = " + peopleId);
                Intent intent = new Intent(Intent.ACTION_VIEW,
                            ContentUris.withAppendedId(Contacts.CONTENT_URI,
                                    Integer.valueOf(peopleId)));
                startActivity(intent);
            }
        };

        public ContactsAdapter() {
            super(SearchKeyBoard.this, R.layout.twelve_key_dialer_list_item, null);
            // mLabelArray =
            // getResources().getTextArray(com.android.internal.R.array.phoneTypes);
        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            View view = super.newView(context, cursor, parent);

            // Get the views to bind to
            ContactsListItemViews views = new ContactsListItemViews();
            views.line1View = (TextView) view.findViewById(R.id.line1);
            views.labelView = (TextView) view.findViewById(R.id.label);
            views.numberView = (TextView) view.findViewById(R.id.number);
            views.photoView = (ImageView) view.findViewById(R.id.photo);
            views.operateButton = (ImageView) view.findViewById(R.id.item_button);

            view.setTag(views);
            return view;
        }

        @Override
        public void bindView(View view, Context context, Cursor c) {
            final ContactsListItemViews views = (ContactsListItemViews) view.getTag();
            views.line1View.setText("");
            views.labelView.setText("");
            views.numberView.setText("");

            views.labelView.setVisibility(View.VISIBLE);
            views.labelView.setText(String.valueOf(c.getCount()));

            /*
             * int id = c.getInt(ID_COLUMN_INDEX); String number =
             * c.getString(NUMBER_COLUMN_INDEX); String formattedNumber =
             * formatPhoneNumber(number); formattedNumber =
             * formattedNumber.replace(',', 'p'); formattedNumber =
             * formattedNumber.replace(';', 'w'); String callerName =
             * c.getString(CALLER_NAME_COLUMN_INDEX); int callerNumberType =
             * c.getInt(CALLER_NUMBERTYPE_COLUMN_INDEX); String
             * callerNumberLabel = c.getString(CALLER_NUMBERLABEL_COLUMN_INDEX);
             * Bitmap photo = null; int data = c.getInt(CALLER_PHOTO_INDEX); //
             * photo =ContactsUtils.loadContactPhoto(context, data, null);
             * //delete the title of seperator // View header =
             * view.findViewById(R.id.header); //
             * header.setVisibility(View.GONE); boolean isCalllog = id%2 == 0;
             * //delete the title of seperator // if(isCalllog && c.isFirst()){
             * // header.setVisibility(View.VISIBLE); // TextView headerText =
             * (TextView)header.findViewById(R.id.header_text); //
             * headerText.setText(R.string.title_calllog); // }else
             * if(!isCalllog && c.isFirst()){ //
             * header.setVisibility(View.VISIBLE); // TextView headerText =
             * (TextView)header.findViewById(R.id.header_text); //
             * headerText.setText(R.string.title_contacts); // }else
             * if(!isCalllog){ // c.moveToPrevious(); // String provCallerName =
             * c.getString(CALLER_NAME_COLUMN_INDEX); //
             * if(TextUtils.isEmpty(provCallerName)){ //
             * header.setVisibility(View.VISIBLE); // TextView headerText =
             * (TextView)header.findViewById(R.id.header_text); //
             * headerText.setText(R.string.title_contacts); // } //
             * c.moveToNext(); // } if(photo != null){
             * views.photoView.setImageBitmap(photo); }else{ //
             * views.photoView.setImageResource
             * (R.drawable.ic_contact_list_picture); } Integer dataId =
             * c.getInt(CALLER_DATA_ID); Log.d(TAG, "CALLER_DATA_ID is >> " +
             * dataId); views.photoView.setTag(dataId.toString()); // Set the
             * text lines if (!isCalllog) { if(!TextUtils.isEmpty(callerName)){
             * views.line1View.setText(callerName); setEcho(c, views.line1View,
             * 1); }else{ views.line1View.setText(formattedNumber); setEcho(c,
             * views.line1View, 0); } views.line1View.setTag(new
             * Boolean(!isCalllog));
             * views.labelView.setVisibility(View.VISIBLE);
             * views.numberView.setVisibility(View.VISIBLE);
             * views.numberView.setText(formattedNumber); setEcho(c,
             * views.numberView, 0); Integer peopleId =
             * c.getInt(CALLER_PEOPLE_ID);
             * views.operateButton.setVisibility(View.VISIBLE);
             * views.operateButton.setTag(peopleId.toString()); //
             * views.operateButton
             * .setImageDrawable(getResources().getDrawable(R.
             * drawable.btn_more));
             * views.operateButton.setOnClickListener(mAddListenerPeople);
             * CharSequence numberLabel = Phones.getDisplayLabel(context,
             * callerNumberType, callerNumberLabel, mLabelArray); if
             * (!TextUtils.isEmpty(numberLabel)) {
             * views.labelView.setText(numberLabel);
             * views.labelView.setVisibility(View.VISIBLE); } else {
             * views.labelView.setVisibility(View.GONE); } } else { String
             * voiceMailNumber =
             * ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE))
             * .getVoiceMailNumber();
             * views.operateButton.setVisibility(View.GONE); if
             * (number.equals(CallerInfo.UNKNOWN_NUMBER)) { number =
             * getString(R.string.unknown); views.line1View.setText(number); }
             * else if (number.equals(CallerInfo.PRIVATE_NUMBER)) { number =
             * getString(R.string.private_num); views.line1View.setText(number);
             * } else if (number.equals(CallerInfo.PAYPHONE_NUMBER)) { number =
             * getString(R.string.payphone); views.line1View.setText(number); }
             * else if (number.equals(voiceMailNumber)) { number =
             * getString(R.string.voicemail); views.line1View.setText(number); }
             * else { // Just a raw number, and no cache, so format it nicely
             * number = formatPhoneNumber(number);
             * views.operateButton.setVisibility(View.VISIBLE);
             * views.operateButton.setTag(number); //
             * views.operateButton.setImageDrawable
             * (getResources().getDrawable(R.drawable.btn_add_more));
             * views.operateButton.setOnClickListener(mAddListener);
             * views.line1View.setText(formattedNumber); setEcho(c,
             * views.line1View, 0); } views.line1View.setTag(new
             * Boolean(!isCalllog)); views.numberView.setVisibility(View.GONE);
             * views.labelView.setVisibility(View.GONE); }
             */
        }

        private void setEcho(Cursor c, TextView text, int type) {
            String inputNumber = mDigitsShow.getText().toString();
            if (TextUtils.isEmpty(inputNumber)) {
                return;
            }

            String numberShort = c.getString(CALLER_NUMBER_SHORT_INDEX);
            String numberFull = c.getString(CALLER_NUMBER_FULL_INDEX);
            String indexShort = c.getString(CALLER_NUMBER_INDEX_SHORT_INDEX);
            String indexFull = c.getString(CALLER_NUMBER_INDEX_FULL_INDEX);

            // When index of pinyin is empty, echo by the rule of number.
            if (TextUtils.isEmpty(numberShort)
                    || TextUtils.isEmpty(numberFull)
                    || TextUtils.isEmpty(indexShort)
                    || TextUtils.isEmpty(indexShort)) {
                type = 0;
            }

            // echo the matched tel-number.
            if (type == 0) {
                String number = text.getText().toString();
                int indexStart = number.indexOf(inputNumber);
                if (indexStart != -1) {
                    StringBuilder echoText = new StringBuilder();
                    echoText.append(number.substring(0, indexStart));
                    echoText.append("<font color=\"#ff0000\">");
                    echoText.append(number.substring(indexStart, indexStart + inputNumber.length()));
                    echoText.append("</font>");
                    echoText.append(number.substring(indexStart + inputNumber.length(),
                            number.length()));
                    text.setText(Html.fromHtml(echoText.toString()));
                    return;
                }

                // if(number.indexOf(inputNumber) == 0){
                // StringBuilder echoText = new StringBuilder();
                // echoText.append("<font color=\"#ff0000\">");
                // echoText.append(number.substring(0, inputNumber.length()));
                // echoText.append("</font>");
                // echoText.append(number.substring(inputNumber.length(),
                // number.length()));
                // text.setText(Html.fromHtml(echoText.toString()));
                // return;
                // }
            } else {
                // echo the matched name
                int indexStart = numberShort.indexOf(inputNumber);
                if (indexStart != -1) {
                    String subIndex = indexShort.substring(indexStart,
                            indexStart + inputNumber.length());
                    SetEchoWithIndex(subIndex, text);
                    return;
                }
                indexStart = numberFull.indexOf(inputNumber);
                if (indexStart != -1) {
                    String subIndex = indexFull.substring(indexStart,
                            indexStart + inputNumber.length());
                    SetEchoWithIndex(subIndex, text);
                    return;
                }
            }
        }

        private void SetEchoWithIndex(String index, TextView name) {
            StringBuilder echoText = new StringBuilder();
            String text = name.getText().toString();
            for (int i = 0; i < text.length(); i++) {
                if (index.contains(String.valueOf((char) ('A' + i)))) {
                    echoText.append("<font color=\"#ff0000\">");
                    echoText.append(text.charAt(i));
                    echoText.append("</font>");
                } else {
                    echoText.append(text.charAt(i));
                }
            }
            name.setText(Html.fromHtml(echoText.toString()));
        }
    }

    private static final class QueryHandler extends AsyncQueryHandler {
        private final WeakReference<SearchKeyBoard> mActivity;

        /**
         * Simple handler that wraps background calls to catch
         * {@link SQLiteException}, such as when the disk is full.
         */
        protected class CatchingWorkerHandler extends AsyncQueryHandler.WorkerHandler {
            public CatchingWorkerHandler(Looper looper) {
                super(looper);
            }

            @Override
            public void handleMessage(Message msg) {
                try {
                    // Perform same query while catching any exceptions
                    super.handleMessage(msg);
                } catch (SQLiteDiskIOException e) {
                    Log.w(TAG, "Exception on background worker thread", e);
                } catch (SQLiteFullException e) {
                    Log.w(TAG, "Exception on background worker thread", e);
                } catch (SQLiteDatabaseCorruptException e) {
                    Log.w(TAG, "Exception on background worker thread", e);
                }
            }
        }

        @Override
        protected Handler createHandler(Looper looper) {
            // Provide our special handler that catches exceptions
            return new CatchingWorkerHandler(looper);
        }

        public QueryHandler(Context context) {
            super(context.getContentResolver());
            mActivity = new WeakReference<SearchKeyBoard>(
                    (SearchKeyBoard) context);
        }

        @Override
        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {

            final SearchKeyBoard activity = mActivity.get();
            if (activity != null && !activity.isFinishing()) {
                final SearchKeyBoard.ContactsAdapter callsAdapter = activity.mAdapter;
                callsAdapter.changeCursor(cursor);
                if (cursor == null || cursor.getCount() < 1) {
                    Message message = activity.mHandler
                            .obtainMessage(activity.NO_CALLLOG_AND_CONTACTS);
                    message.sendToTarget();
                } else {
                    Message message = activity.mHandler
                            .obtainMessage(activity.HAVE_CALLLOG_AND_CONTACTS);
                    message.sendToTarget();
                }
            } else {
                if (null != cursor)
                    cursor.close();
            }
        }
    }

    private void setKeyBoardStyle(int style) {
        if (style == 1) {
            mSearchLayout.setVisibility(View.VISIBLE);
            mDone.setVisibility(View.VISIBLE);
            tableRow.setVisibility(View.GONE);
            mCall.setVisibility(View.GONE);
            mSms.setVisibility(View.GONE);
        } else {
            mSearchLayout.setVisibility(View.GONE);
            mDone.setVisibility(View.GONE);
            tableRow.setVisibility(View.VISIBLE);
            mCall.setVisibility(View.VISIBLE);
            mSms.setVisibility(View.VISIBLE);
        }
    }

    /**
     * @return true if the phone is a CDMA phone type
     */
    // private boolean phoneIsCdma() {
    // boolean isCdma = false;
    // try {
    // ITelephony phone =
    // ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
    // if (phone != null) {
    // isCdma = (phone.getActivePhoneType() ==
    // TelephonyManager.PHONE_TYPE_CDMA);
    // }
    // } catch (RemoteException e) {
    // Log.w(TAG, "phone.getActivePhoneType() failed", e);
    // }
    // return isCdma;
    // }

    // /**
    // * @return true if the phone state is OFFHOOK
    // */
    // private boolean phoneIsOffhook() {
    // boolean phoneOffhook = false;
    // try {
    // ITelephony phone =
    // ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
    // if (phone != null) phoneOffhook = phone.isOffhook();
    // } catch (RemoteException e) {
    // Log.w(TAG, "phone.isOffhook() failed", e);
    // }
    // return phoneOffhook;
    // }

    /**
     * Initialize the vibration parameters.
     * 
     * @param r The Resources with the vibration parameters.
     */
    // private void initVibrationPattern(Resources r) {
    // int[] pattern = null;
    // try {
    // mVibrateOn = r.getBoolean(R.bool.config_enable_dialer_key_vibration);
    // pattern =
    // r.getIntArray(com.android.internal.R.array.config_virtualKeyVibePattern);
    // if (null == pattern) {
    // Log.e(TAG, "Vibrate pattern is null.");
    // mVibrateOn = false;
    // }
    // } catch (Resources.NotFoundException nfe) {
    // Log.e(TAG, "Vibrate control bool or pattern missing.", nfe);
    // mVibrateOn = false;
    // }
    //
    // if (!mVibrateOn) {
    // return;
    // }
    //
    // // int[] to long[] conversion.
    // mVibratePattern = new long[pattern.length];
    // for (int i = 0; i < pattern.length; i++) {
    // mVibratePattern[i] = pattern[i];
    // }
    // }

    /**
     * This function return true if Wait menu item can be shown otherwise
     * returns false. Assumes the passed string is non-empty and the 0th index
     * check is not required.
     */
    private boolean showWait(int start, int end, String digits) {
        if (start == end) {
            // visible false in this case
            if (start > digits.length())
                return false;

            // preceding char is ';', so visible should be false
            if (digits.charAt(start - 1) == ';')
                return false;

            // next char is ';', so visible should be false
            if ((digits.length() > start) && (digits.charAt(start) == ';'))
                return false;
        } else {
            // visible false in this case
            if (start > digits.length() || end > digits.length())
                return false;

            // In this case we need to just check for ';' preceding to start
            // or next to end
            if (digits.charAt(start - 1) == ';')
                return false;
        }
        return true;
    }

}
